﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PayloadTracker
{
    public partial class Main : Form
    {
        private NewFlight m_NewFlightDlg;
        private FlightCollection m_Flights;
        private System.Threading.Thread m_UpdateThread;

        private bool m_Tracking;
        private APRS.APRSConfiguration m_APRSConfiguration;
        private List<APRS.IAPRSProvider> m_TrackedProviders;

        public Main()
        {
			//System.Diagnostics.Debug.Listeners.Add(new System.Diagnostics.ConsoleTraceListener());
			
            m_TrackedProviders = new List<PayloadTracker.APRS.IAPRSProvider>();
            m_APRSConfiguration = PayloadTracker.APRS.APRSConfiguration.Load(Settings.Default["APRSProvidersFile"] as string);
            m_Tracking = false;
            InitializeComponent();
        }
        private void Main_Load(object sender, EventArgs e)
        {
            m_Flights = new FlightCollection();
            m_NewFlightDlg = new NewFlight(m_APRSConfiguration);
            m_NewFlightDlg.OnNewFlight += new OnNewFlightDelegate(m_NewFlightDlg_OnNewFlight);

            m_MapPanel.OnZoomChanged += new OnZoomChangedDelegate(m_MapPanel_OnZoomChanged);
            this.MouseWheel += new MouseEventHandler(Main_MouseWheel);

            m_UpdateThread = new System.Threading.Thread(new System.Threading.ThreadStart(UpdateThreadLoop));
            m_UpdateThread.Start();



        }
        private void Main_FormClosed(object sender, FormClosedEventArgs e)
        {
            //TODO: Flush all and save.
           // m_APRSConfiguration.Save(Settings.Default["APRSProvidersFile"] as string);
            Application.Exit();
        }

        #region Tool Strips
        private void newFlightToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_NewFlightDlg.ShowDialog(this);
        }
        void m_NewFlightDlg_OnNewFlight(Flight flight)
        {
            
            AddFlight(flight);
            saveFlightsToolStripMenuItem.Enabled = true;
        }
        private void loadFlightsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var ofd = new OpenFileDialog();
            ofd.Filter = "All Files (*.*)|*.*";
            ofd.RestoreDirectory = true;
            ofd.CheckFileExists = true;

            if(ofd.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    var fc = FlightCollection.Load(ofd.FileName);

                    foreach (var f in fc)
                        AddFlight(f);
                }
                catch (System.Exception ex)
                {
                    Logger.LOG.Error("Failed to load saved flights due to: " + ex.ToString());
                }
            }

            m_MapPanel.Invalidate();

        }

        private void saveFlightsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var sfd = new SaveFileDialog();
            sfd.Filter = "Xml Files (*.xml)|*.xml|All Files (*.*)|*.*";
            sfd.RestoreDirectory = true;

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    m_Flights.Save(sfd.FileName);
                }
                catch (System.Exception ex)
                {
                    Logger.LOG.Warn("Failed to save flights due to: " + ex.Message.ToString());
                    Logger.LOG.Error("Failed to save flights due to: " + ex.ToString(), false);
                }
                
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void beginTrackingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!m_Tracking)
            {
                m_Tracking = true;

                lock(m_Flights)
                {
                    foreach (Flight f in m_Flights)
                        f.Provider.Start();
                }


                stopTrackingToolStripMenuItem.Enabled = true;
                beginTrackingToolStripMenuItem.Enabled = false;
            }
        }

        private void stopTrackingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_Tracking = false;
            lock(m_TrackedProviders)
            {
                foreach (APRS.IAPRSProvider p in m_TrackedProviders)
                    p.Stop();

            }
            beginTrackingToolStripMenuItem.Enabled = true;
            stopTrackingToolStripMenuItem.Enabled = false;

        }
        private void flightsToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            flightsToolStripMenuItem.DropDownItems.Clear();

            foreach (Flight f in m_Flights)
            {
                if (f.Callsign != null)
                {
                    ToolStripMenuItem tsmi = new ToolStripMenuItem(f.Callsign);
                    tsmi.Tag = f;
                    tsmi.Click += new EventHandler(tsmi_Click);
                    flightsToolStripMenuItem.DropDownItems.Add(tsmi);
                }
            }
        }

        void tsmi_Click(object sender, EventArgs e)
        {
            Flight f = (sender as ToolStripMenuItem).Tag as Flight;

            if (f.CurrentTelemetry != null)
                m_MapPanel.SetCenter(f.CurrentTelemetry.Position);
        }

        private void tilePrecacherToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var precacher = new OSM.TilePrecacherDialog();
            precacher.SetCenter(m_MapPanel.Center);
            precacher.Show(this);
        }

        #endregion

        #region Zoom
        void m_MapPanel_OnZoomChanged(int Zoom)
        {
            tbZoom.Value = Zoom;
        }

        void Main_MouseWheel(object sender, MouseEventArgs e)
        {
            if(tbZoom.Value < tbZoom.Maximum && e.Delta > 0)
            {
                tbZoom.Value++;
                tbZoom_Scroll(null, null);
            }
            else if(tbZoom.Value > tbZoom.Minimum && e.Delta < 0)
            {
                tbZoom.Value--;
                tbZoom_Scroll(null, null);
            }

        }

        private void tbZoom_Scroll(object sender, EventArgs e)
        {

            m_MapPanel.Zoom = tbZoom.Value;
        }
        #endregion
        private void UpdateThreadLoop()
        {
            Logger.LOG.WriteLine("Update Thread Started...");
            while (this.Visible)
            {
                lock (m_TrackedProviders)
                {
                    foreach (APRS.IAPRSProvider p in m_TrackedProviders)
                        try
                        {
                            p.Tick();
                        }
                        catch (System.Exception ex)
                        {
                            Logger.LOG.Error("Cannot update " + p.Name + " due to: " + ex.ToString());
                        }
                        
                }
                
                System.Threading.Thread.Sleep(100);
            }
            Logger.LOG.WriteLine("Update Thread TERMINATING!");
        }

        private void AddFlight(Flight flight)
        {

            
            lock (m_TrackedProviders)
            {
                if (!m_TrackedProviders.Contains(flight.Provider))
                {
                    flight.Provider.APRSUpdate += new PayloadTracker.APRS.APRSUpdateDelegate(Provider_APRSUpdate);
                    flight.Provider.Initialize();
                    m_TrackedProviders.Add(flight.Provider);
                }
            }

            if (m_Tracking)
            {
                flight.Provider.Start();
            }
            else
                beginTrackingToolStripMenuItem.Enabled = true;


            if (!flight.Provider.TrackAll)
                TrackFlight(flight);

        }

        private void TrackFlight(Flight flight)
        {
            lock (m_Flights)
                m_Flights.Flights.Add(flight);

            flight.OnUpdate += new FlightUpdateDelegate(flight_OnUpdate);
            m_MapPanel.Flights = m_Flights;
        }
        void Provider_APRSUpdate(PayloadTracker.APRS.IAPRSProvider sender, PayloadTracker.APRS.APRSBeacon beacon)
        {
            if (!sender.TrackAll)
                return;

            foreach (Flight f in m_Flights)
                if (beacon.Callsign.ToUpper().Trim() == f.Callsign.ToUpper().Trim())
                    return;
            
            //need to add a new flight.
            TrackFlight(new Flight(sender, beacon));

        }

        void flight_OnUpdate(Flight flight, PayloadTracker.APRS.APRSBeacon beacon)
        {   
            m_StatusText.Text = beacon.ToString();
            m_MapPanel.Invalidate();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox ab = new AboutBox();
            ab.Show(this);
        }

        private void aPRSTrafficToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RawTraffic rt = new RawTraffic();
            rt.lines.Add("not working yet...");
            rt.Show(this);
        }

        private void m_MapPanel_MouseMove(object sender, MouseEventArgs e)
        {
            var coord = m_MapPanel.PixelPositionToCoordinate(e.Location);
            m_StatusText.Text = "Mouse On: " + coord.ToString();
        }



    }
}
